package com.pktechan.api.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * @program: cloudfloating
 * @description: redis连接池工具类
 * @author: qx.zhang
 * @create: 2021-03-11 16:22
 **/
@Configuration
public class JedisPoolUtils {

    private static Logger logger = LoggerFactory.getLogger(JedisPoolUtils.class);

    //访问密码
    private static String password;

//    @Value("${redis.password}")
//    public void setAuth(String password) {
//        this.password = password;
//    }

    //Redis的端口号
    private static int port;

    @Value("${redis.port}")
    public void setPort(int port) {
        this.port = port;
    }

    private static String host;

    @Value("${redis.host}")
    public void setHost(String host) {
        JedisPoolUtils.host = host;
    }

    /**
     * 可用连接实例的最大数目，默认为8
     * 如果赋值为-1，则表示不限制;如果pool已经分配了maxActive个jedis实例，则此时pool的状态为exhausted(耗尽)。
     */
    private static int maxActive;

    @Value("${redis.jedis.pool.max-active}")
    public void setMaxActive(int maxActive) {
        this.maxActive = maxActive;
    }

    /**
     * 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例，默认值也是8
     */
    private static int maxIdle;

    @Value("${redis.jedis.pool.max-idle}")
    public void setMaxIdle(int maxIdle) {
        this.maxIdle = maxIdle;
    }

    /**
     * 控制一个pool最少有多少个状态为idle(空闲的)的jedis实例，默认值也是8
     */
    private static int minIdle;

    @Value("${redis.jedis.pool.min-idle}")
    public void setMinIdle(int minIdle) {
        this.minIdle = minIdle;
    }

    /**
     * 等待可用连接的最大时间，单位毫秒，默认值为-1，表示永不超时。如果超过等待时间，则直接抛出JedisConnectionException；
     */
    private static int maxWait;

    @Value("${redis.jedis.pool.max-wait}")
    public void setMaxWait(int maxWait) {
        this.maxWait = maxWait;
    }

    /**
     * 超时时间,当池内没有可用对象返回时，最大等待时间
     */
    private static int timeout;
    @Value("${redis.timeout}")
    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    /**
     * 在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的；
     */
    private static boolean testOnBorrow;
    @Value("${redis.jedis.pool.test-on-borrow}")
    public void setTestOnBorrow(boolean testOnBorrow) {
        this.testOnBorrow = testOnBorrow;
    }

    /**
     * 在return给pool时，是否提前进行validate操作；
     */
    private static boolean testOnReturn;
    @Value("${redis.jedis.pool.test-on-return}")
    public void setTestOnReturn(boolean testOnReturn) {
        this.testOnReturn = testOnReturn;
    }

    /**
     * 如果为true，表示有一个idle object evitor线程对idle object进行扫描，如果validate失败，此object会被从pool中drop掉；这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义；
     */
    private static boolean testWhileIdle;
    @Value("${redis.jedis.pool.test-while-idle}")
    public void setTestWhileIdle(boolean testWhileIdle) {
        this.testWhileIdle = testWhileIdle;
    }

    private static JedisPool jedisPool = null;

    /**
     * 初始化Redis连接池
     */
    private static void createJedisPool() {
        try {
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxTotal(maxActive);
            config.setMaxIdle(maxIdle);
            config.setMinIdle(minIdle);
            config.setMaxWaitMillis(maxWait);
            config.setTestOnBorrow(testOnBorrow);//使用时进行扫描，确保都可用
            config.setTestWhileIdle(testWhileIdle);//Idle时进行连接扫描
            config.setTestOnReturn(testOnReturn);//还回线程池时进行扫描
            //表示idle object evitor两次扫描之间要sleep的毫秒数
            config.setTimeBetweenEvictionRunsMillis(30000);
            //表示idle object evitor每次扫描的最多的对象数
            config.setNumTestsPerEvictionRun(50);
            //表示一个对象至少停留在idle状态的最短时间，然后才能被idle object evitor扫描并驱逐；这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义
            config.setMinEvictableIdleTimeMillis(60000);
            if (StringUtil.isValid(password)) {
                jedisPool = new JedisPool(config, host, port, timeout, password);
            } else {
                jedisPool = new JedisPool(config, host, port, timeout);
            }
        } catch (Exception e) {
            logger.error("First create JedisPool error : " + e);
            try {
                //如果第一个IP异常，则访问第二个IP
                JedisPoolConfig config = new JedisPoolConfig();
                config.setMaxTotal(maxActive);
                config.setMaxIdle(maxIdle);
                config.setMaxWaitMillis(maxWait);
                config.setTestOnBorrow(testOnBorrow);
                jedisPool = new JedisPool(config, host, port, timeout, password);
            } catch (Exception e2) {
                logger.error("Second create JedisPool error : " + e2);
            }
        }
    }

    /**
     * 在多线程环境同步初始化
     */
    private static synchronized void poolInit() {
        if (jedisPool == null) {
            createJedisPool();
        }
    }

    /**
     * 同步获取Jedis实例
     *
     * @return Jedis
     */
    public static Jedis getJedis() {
        if (jedisPool == null) {
            poolInit();
        }
        Jedis jedis = null;
        try {
            if (jedisPool != null) {
                jedis = jedisPool.getResource();
            }
        } catch (Exception e) {
            logger.error("Get jedis Error : " + e.getMessage(), e);
        }
        return jedis;
    }

    /**
     * 释放jedis资源
     *
     * @param jedis
     */
    public static void returnResource(final Jedis jedis) {
//        logger.debug("执行释放jedis资源方法returnResource:");
        if (jedis != null && jedisPool != null) {
            jedis.close();
            //自Jedis3.0版本后jedisPool.returnResource(final Jedis resource)遭弃用,官方重写了Jedis的close()方法用以代替
//            jedisPool.returnResource(jedis);
        }
    }

    /**
     * 关闭连接池
     */
    public static void closePool() {
        if (jedisPool != null) {
            jedisPool.close();
        }
    }

}
